{
 "metadata": {
  "name": "",
  "signature": "sha256:7c2c38aa2211726bcf4e2002499638e6687b267df5c39bb392903ea19e7e348a"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "heading",
     "level": 1,
     "metadata": {},
     "source": [
      "Namespaces"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from planout.namespace import SimpleNamespace\n",
      "from planout.experiment import SimpleExperiment, DefaultExperiment\n",
      "from planout.ops.random import *\n",
      "import pandas as pd"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Namespaces are a way to manage multiple simultaneous or follow-on experiments. `Namespace` objects look like `Experiment` objects, but randomly assign primary units (e.g., users) to experiments. Units not assigned to experiments are given a default value, and are not logged."
     ]
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "Basic principles of PlanOut namespaces"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "* Namespaces represent a set of related parameters. Experiments in the same namespaces are necessarily _mutually exclusive_.\n",
      "* Never modify an already running experiment\n",
      "* New experiments are registered and turned off through the namespace\n",
      "* Experiments are always analyzed separately."
     ]
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "Multiple experiments"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Let's suppose we're iteratively running experiments, where we create a new experiment every few weeks as we learn things."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "class V1(SimpleExperiment):\n",
      "  def assign(self, params, userid):\n",
      "    params.banner_text = UniformChoice(\n",
      "      choices=['Hello there!', 'Welcome!'],\n",
      "      unit=userid)\n",
      "\n",
      "class V2(SimpleExperiment):\n",
      "  def assign(self, params, userid):\n",
      "    params.banner_text = WeightedChoice(\n",
      "      choices=['Hello there!', 'Welcome!'],\n",
      "      weights=[0.8, 0.2],\n",
      "      unit=userid)\n",
      "\n",
      "class V3(SimpleExperiment):\n",
      "  def assign(self, params, userid):\n",
      "    params.banner_text = WeightedChoice(\n",
      "      choices=['Nice to see you!', 'Welcome back!'],\n",
      "      weights=[0.8, 0.2],\n",
      "      unit=userid)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "A default experiment"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "We also specify the experience of users not assigned to any experiments. Default experiments can return default key-value pairs."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "class DefaultBannerExperiment(DefaultExperiment):\n",
      "  def get_default_params(self):\n",
      "    return {'banner_text': 'Generic greetings!'}"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "Implementing a namespace with `SimpleNamespace`"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Here is a namespace. It defines a name, the primary unit which gets hashed into conditions, the number of segments (should be 10,000 or 100,000 in production settings)."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "class BannerNamespace(SimpleNamespace):\n",
      "  def setup(self):\n",
      "    self.name = 'banner'\n",
      "    self.primary_unit = 'userid'\n",
      "    self.num_segments = 100\n",
      "    self.default_experiment_class = DefaultBannerExperiment\n",
      "    \n",
      "  def setup_experiments(self):\n",
      "    self.add_experiment('first version phase 1', V1, 30)\n",
      "    self.add_experiment('first version phase 2', V1, 10)\n",
      "    self.add_experiment('second version', V2, 40)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 47
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Try out a few users"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "BannerNamespace(userid=6).get('banner_text')"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 48,
       "text": [
        "'Hello there!'"
       ]
      }
     ],
     "prompt_number": 48
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "for i in xrange(20):\n",
      "    print BannerNamespace(userid=i).get('banner_text')"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "Welcome!\n",
        "Hello there!\n",
        "Generic greetings!\n",
        "Hello there!\n",
        "Generic greetings!\n",
        "Hello there!\n",
        "Hello there!\n",
        "Welcome!\n",
        "Hello there!\n",
        "Welcome!\n",
        "Generic greetings!\n",
        "Hello there!\n",
        "Generic greetings!\n",
        "Generic greetings!"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "Hello there!\n",
        "Generic greetings!\n",
        "Hello there!\n",
        "Generic greetings!\n",
        "Hello there!\n",
        "Hello there!\n"
       ]
      }
     ],
     "prompt_number": 50
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Now take a look at your local directory."
     ]
    },
    {
     "cell_type": "heading",
     "level": 4,
     "metadata": {},
     "source": [
      "Underneeth the hood"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "ns = BannerNamespace(userid=2)\n",
      "ns.get_segment()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "ns.segment_allocations.get(ns.get_segment, 'no experiment allocated to segment')"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "allocations = pd.DataFrame(ns.segment_allocations.items(), columns=['segment', 'experiment'])\n",
      "print allocations[:8]\n",
      "print allocations.groupby('experiment').agg(len)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    }
   ],
   "metadata": {}
  }
 ]
}